\chapter{Пространства имен}

\section{Имена в контексте C++}

Имена в плюсах могут быть у следующих объектов:

\begin{itemize}
\item Методы/функции

\item Классы/типы

\item Поля классов и имена переменных

\item typedef-ы (псевдонимы)
\end{itemize}

\section{Предистория}

Пространства имен, не самая старая конструкция C++, раньше для ограничения областей вилимости в C++ использовались структуры, которые
позволяли ограничивать области видимости, разделять имена и т. п. Но теперь те старые добрые времена прошли и в плюсах появились пространства
имен.

\section{Использования}

Объявление namespace:

\begin{lstlisting}
namespace outer_namespace
{
	...
	namespace inner_namespace
	{
		...
	}
	...
}
\end{lstlisting}

Видно, что namespace может быть вложенным, обращаться к полю namespace-а снаружи можно через квалифицированное имя:

\begin{lstlisting}
outer_namespace::inner_namespace::some_function();
\end{lstlisting}

имя может быть относительным, например, при обращении из outer\_namespace к функции inner\_namespace, можно писать:

\begin{lstlisting}
inner_namespace::some_function();
\end{lstlisting}

Существует глобальный namespace, к которому обращаются просто через:

\begin{lstlisting}
::some_global_variable;
\end{lstlisting}

С некоторыми объектами C++ связаны пространства имен, очевидно с классами и структурами связаны namespace-ы, но есть свои namespace-ы
у каждого блока кода, у циклов (for, while, do ... while), у конструкций ветвления.

\section{Поиск имен}

При поиске метода, класса или переменной в первую очередь ищется имя, и если первое найденное имя не соответсвует функции,
если мы хотим найти функцию, то случится беда и тут стоит сделать еще одно маленькое замечание - namespace ограничивает
перегрузку, так как если, например, в двух namespace-ах ns1 и ns2 определены различные варианты функции function, и первой
мы находим имя function в ns1, то при поиске подходящего варианта будут использованы только функции определенные в ns1, даже
если подходящая функция не найдется.

Классический пример:

\begin{lstlisting}
class A
{
	...
	void f(int);
	...
};

class B : public A
{
	...
	void f(double);
	...
};

B b;
b.f(10); //f(double) will be called
\end{lstlisting}

В примере выше имя f перекрывается в пространстве имен класса наследника и дальше не ищется в родительском классе, чтобы исправить
можно поступить следующим образом:

\begin{lstlisting}
class B : public A
{
	...
	using A::f;
	void f(double);
	...
};
\end{lstlisting}

using позволяет вложить родительский namespace класса A в namespace класса B, что решает проблему и теперь найдется именна функция f(int).

Есть так же возможность подключить все имена из пространсва имен (например, std):

\begin{lstlisting}
using namespace std;
\end{lstlisting}

На самом деле эта директива отличается от предыдущей директивы using, так как using namespace добавляет (хотя не совсем, доступность будет
локальной) имена namespace-а в ближайшего общего предка-namespace-а (в крайнем случае все будет добавлено в глобальный namespace и это как
правило печально).

Поиск имен происходит только при неквалифицированном имени, т. е. если мы явно вызовем:

\begin{lstlisting}
B b;
b.A::f(10);
\end{lstlisting}

никакого поиска имен не будет.

Кроме того конфиликты выявляются только в момент использования, но не в момент подключения namespace-ов, т. е. если namespace-ы ns1 и ns2
содержат имя function, то проблема будет возникать только в момент использования function, но не при одновременном подключении ns1 и ns2.

\section{Безымянный namespace}

Позволяет избегать обяхвления имени как static, так как слово static является устаревшим. Используется это примерно так:

\begin{lstlisting}
namespace
{
	...
	void f();
	...
}

void f()
{
	...
}
\end{lstlisting}
